/**
 * Object类是所有Java类的根父类，每个类都隐式或显式地继承自Object类。
 * 本程序用于测试Object类中的一些重要方法，包括toString()、equals()、hashCode()、getClass()和clone()。
 */
package day19.ObjectClass;

public class ObjectTest {
    /**
     * 程序入口点，用于测试Object类的各种方法
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 创建对象实例来测试Object类的方法
        // person1和person2是内容相同但地址不同的两个对象
        // person3是person1的引用，指向同一个对象
        Person person1 = new Person("张三", 25);
        Person person2 = new Person("张三", 25);
        Person person3 = person1;

        // 测试toString()方法
        // toString()方法用于返回对象的字符串表示形式
        System.out.println("=== toString() 方法测试 ===");
        System.out.println("person1: " + person1.toString());
        System.out.println("person2: " + person2.toString());

        // 测试equals()方法
        // equals()方法用于比较两个对象是否相等
        System.out.println("\n=== equals() 方法测试 ===");
        // person1和person2内容相同但为不同对象，结果取决于equals方法的实现
        System.out.println("person1.equals(person2): " + person1.equals(person2));
        // person1和person3指向同一对象，结果应为true
        System.out.println("person1.equals(person3): " + person1.equals(person3));
        // == 比较的是对象的引用（内存地址），person1和person2地址不同
        System.out.println("person1 == person2: " + (person1 == person2));
        // person1和person3引用同一对象，地址相同
        System.out.println("person1 == person3: " + (person1 == person3));

        // 测试hashCode()方法
        // hashCode()方法返回对象的哈希码值，通常用于哈希表等数据结构中
        System.out.println("\n=== hashCode() 方法测试 ===");
        // person1的哈希码值
        System.out.println("person1.hashCode(): " + person1.hashCode());
        // person2的哈希码值
        System.out.println("person2.hashCode(): " + person2.hashCode());
        // person3与person1为同一对象，哈希码值应相同
        System.out.println("person3.hashCode(): " + person3.hashCode());

        // 测试getClass()方法
        // getClass()方法返回对象运行时的Class对象
        System.out.println("\n=== getClass() 方法测试 ===");
        // 获取person1对象的Class对象
        System.out.println("person1.getClass(): " + person1.getClass());
        // 获取类的完整名称（包含包名）
        System.out.println("类名: " + person1.getClass().getName());

        // 测试clone()方法
        // clone()方法用于创建并返回对象的一个副本
        System.out.println("\n=== clone() 方法测试 ===");
        try {
            // 调用person1的clone()方法创建一个新对象person4
            Person person4 = (Person) person1.clone();
            System.out.println("克隆成功:");
            // 打印原对象和克隆对象
            System.out.println("person1: " + person1);
            System.out.println("person4: " + person4);
            // 使用equals方法比较原对象和克隆对象的内容
            System.out.println("person1.equals(person4): " + person1.equals(person4));
            // 使用==比较原对象和克隆对象的引用，应为false，因为是两个不同的对象
            System.out.println("person1 == person4: " + (person1 == person4));
        } catch (CloneNotSupportedException e) {
            // 捕获克隆不支持异常
            System.out.println("克隆失败: " + e.getMessage());
        }
    }
}

/**
 * Person类用于演示Object类方法的重写
 * 实现了Cloneable接口以支持克隆操作
 */
class Person implements Cloneable {
    // 姓名属性，使用private修饰符封装数据
    private String name;
    // 年龄属性，使用private修饰符封装数据
    private int age;

    /**
     * Person类的构造方法
     * @param name 人的姓名
     * @param age 人的年龄
     */
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 重写toString方法
     * Object类的默认toString()方法返回"类名@哈希码"格式的字符串
     * 重写后可以返回更有意义的对象信息
     * @return 包含对象信息的字符串
     */
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    /**
     * 重写equals方法
     * Object类的默认equals()方法使用==比较对象引用
     * 重写后可以根据对象的内容来判断是否相等
     * @param obj 要比较的对象
     * @return 如果两个对象内容相同则返回true，否则返回false
     */
    @Override
    public boolean equals(Object obj) {
        // 如果两个引用指向同一个对象，则直接返回true
        if (this == obj) return true;
        // 如果传入的对象为null或者两个对象的类型不同，则返回false
        if (obj == null || getClass() != obj.getClass()) return false;
        // 将传入的对象强制转换为Person类型
        Person person = (Person) obj;
        // 比较两个对象的属性值是否都相等
        return age == person.age && name.equals(person.name);
    }

    /**
     * 重写hashCode方法
     * 当重写了equals()方法后，通常也需要重写hashCode()方法
     * 以保证相等的对象具有相同的哈希码
     * @return 对象的哈希码值
     */
    @Override
    public int hashCode() {
        // 根据name和age计算哈希码
        // 使用name的哈希码乘以31再加上age作为最终的哈希码
        // 31是一个奇素数，有助于减少哈希冲突
        return name.hashCode() * 31 + age;
    }

    /**
     * 重写clone方法
     * Object类的clone()方法是protected的，需要重写并提升访问权限
     * 实现Cloneable接口后才能调用clone()方法
     * @return 克隆出的新对象
     * @throws CloneNotSupportedException 当对象不支持克隆时抛出此异常
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 调用父类Object的clone()方法实现浅拷贝
        return super.clone();
    }

    /**
     * 获取姓名的getter方法
     * @return 姓名
     */
    public String getName() {
        return name;
    }

    /**
     * 获取年龄的getter方法
     * @return 年龄
     */
    public int getAge() {
        return age;
    }
}